#include <vector>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include<queue>
using namespace std;

namespace BlockQueueModule
{
    template <typename T> // 创建模板
    class BlockQueue
    {
    public:
        BlockQueue(int cap) : _cap(cap)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
        }

        bool IsFull()
        {
            return _cap == _q.size(); // 满返回true
        }

        bool IsEmpty()
        {
            return _q.size() == 0;
        }

        void Equeue(const T &in) // 生产者向队列中插入数据
        {
            pthread_mutex_lock(&_mutex);
            while (IsFull())
            {
                std::cout<<"生产者进入等待"<<std::endl;
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);
                std::cout<<"生产者被唤醒"<<std::endl;
                _pwait_num--;
            }
            //此时说明没有满，或者是被唤醒了，肯定有空位置
            _q.push(in);
            //刚刚生产肯定有数据
            if(_cwait_num)
            {
                std::cout<<"叫醒消费者"<<std::endl;
                pthread_cond_signal(&_consumer_cond);//唤醒消费者
            }
            pthread_mutex_unlock(&_mutex);
        }

        void Pop(T &out)
        {
            pthread_mutex_lock(&_mutex);
            while(IsEmpty())//当队列中数据为空
            {
                std::cout<<"消费者进入等待"<<std::endl;
                _cwait_num++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                std::cout<<"消费者被唤醒"<<std::endl;
                _cwait_num--;
            }
            out = _q.front();
            _q.pop();
            //此时说明队列有空位置，唤醒生产者
            if(_pwait_num)
            {
                std::cout<<"叫醒生产者"<<std::endl;
                pthread_cond_signal(&_productor_cond);
            }

            pthread_mutex_unlock(&_mutex);
        }

        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
        }

    private:
        std::queue<T> _q;               // 保存数据的容器，临界资源
        int _cap;                       // 队列的大小
        pthread_cond_t _productor_cond; // 生产者条件变量
        pthread_cond_t _consumer_cond;  // 消费者条件变量
        pthread_mutex_t _mutex;

        int _cwait_num;
        int _pwait_num;
    };
}